package com.github.pig.wxapi.service;

import java.net.URL;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.github.pig.wxapi.common.config.AliyunOssConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;

/**
 * 阿里云OSS操作
 *
 * @author zhanghengchang
 * @date 2018/3/20
 */
@Service
public class OssService {

    private static Logger logger = LoggerFactory.getLogger(OssService.class);

    @Autowired
    private AliyunOssConfig aliyunOssConfig;

    private OSSClient ossClient;

    /**
     * 获得影像URL
     *
     * @param key 影像文件uri
     * @return
     */
    public String getPreSignedUrl(String key) {
        // 设置URL过期时间
        Date expiration = new Date(System.currentTimeMillis() + aliyunOssConfig.getDownloadExpireTime() * 1000);
        // 生成URL
        URL url = this.getOssClient().generatePresignedUrl(aliyunOssConfig.getBucketName(), key, expiration);

        String urlStr = url.toString();
        // 代理服务器
        if (aliyunOssConfig.isUseProxy()) {
            urlStr = urlStr.replaceAll(aliyunOssConfig.getDownloadHost(), aliyunOssConfig.getProxyUrl());
        }

        return urlStr;
    }

    /**
     * Web文件直传时获得Policy
     *
     * @param uploadDir 上传路径
     * @return 上传用Policy json
     */
    public JSONObject getUploadPolicy(String uploadDir) {
        try {
            long expireEndTime = System.currentTimeMillis() + aliyunOssConfig.getUploadExpireTime() * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, uploadDir);

            String postPolicy = this.getOssClient().generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = this.getOssClient().calculatePostSignature(postPolicy);

            Map<String, String> respMap = new LinkedHashMap<>();
            respMap.put("accessid", aliyunOssConfig.getAccessKeyId());
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", uploadDir);
            respMap.put("host", aliyunOssConfig.getUploadHost());
            respMap.put("expire", String.valueOf(expireEndTime / 1000));

            return (JSONObject) JSONObject.toJSON(respMap);
        } catch (Exception e) {
            logger.error(e.getMessage());
            return null;
        }
    }

    /**
     * 实例化OSSClient
     *
     * @return OSSClient实例
     */
    public OSSClient getOssClient() {
        if (this.ossClient == null) {
            // 创建ClientConfiguration实例
            ClientConfiguration conf = new ClientConfiguration();
            // 关闭CNAME选项
            conf.setSupportCname(false);
            // 创建OSSClient实例
            this.ossClient = new OSSClient(aliyunOssConfig.getEndpoint(),
                    new DefaultCredentialProvider(aliyunOssConfig.getAccessKeyId(), aliyunOssConfig.getAccessKeySecret()),
                    conf);
        }
        return this.ossClient;
    }

    public JSONObject getStsToken(String uploadDir) {
       JSONObject respMap = new JSONObject();
        String endpoint = "sts.aliyuncs.com";
        String accessKeyId = aliyunOssConfig.getAccessKeyId();
        String accessKeySecret = aliyunOssConfig.getAccessKeySecret();
        String roleArn = "acs:ram::1194904104777685:role/aliyunosstokengeneratorrole";
        String roleSessionName = "external-username";
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:*\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        try {
            // Init ACS Client
            DefaultProfile.addEndpoint(endpoint, "", "Sts", endpoint);
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            // Optional
            request.setPolicy(policy);
            final AssumeRoleResponse response = client.getAcsResponse(request);
            respMap.put("accessid", response.getCredentials().getAccessKeyId());
            respMap.put("policy", response.getCredentials().getSecurityToken());
            respMap.put("signature", response.getCredentials().getAccessKeySecret());
            respMap.put("dir", uploadDir);
            respMap.put("host", aliyunOssConfig.getUploadHost());
            respMap.put("expire", response.getCredentials().getExpiration());
            return respMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
